/**************************************************************************** 
* 
* Copyright (c) 2023  C*Core -   All Rights Reserved  
* 
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED, 
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* 
* PROJECT     : CCFC2011BC           
* DESCRIPTION : ECSM demo code 
* HISTORY     : Initial version.
* @file     ecsm_demo.h
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/
#include "ecsm_demo.h"
#include "flash_lld.h"
#include "intc_lld.h"
#include "led_hw.h"

static uint32_t ecc_flashAddress;
static uint32_t ecc_flashMasterNum;
static uint32_t ecc_flashAttributes;
static uint32_t ecc_flashData;

static uint32_t ecc_ramAddress;
static uint32_t ecc_ramSyndrome;
static uint32_t ecc_ramMasterNum;
static uint32_t ecc_ramAttributes;
static uint32_t ecc_ramData;

/*******************************************************************************
 * @brief      ECSM_Error
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ECSM_Error(void)
{
    while (1)
    {
        LED_Set(LED3, LED_OFF);
        delayms(500U);
        LED_Set(LED3, LED_ON);
        delayms(500U);
    }
}


/*******************************************************************************
 * @brief      Read ECSM register and Print.
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ECSM_RegisterRead_Demo(void) /* PRQA S 3219 */
{
    vuint8_t reg8;
    vuint16_t reg16;
    vuint32_t reg32;

    reg16 = ECSM.PCT.R;
    PSPRINTF("\n PCT = 0x%x!\n", reg16);

    reg16 = ECSM.REV.R;
    PSPRINTF("\n REV = 0x%x!\n", reg16);

    reg32 = ECSM.IOPMC.R;
    PSPRINTF("\n IOPMC = 0x%x!\n", reg32);

    reg8 = ECSM.MIR.R;
    PSPRINTF("\n MIR = 0x%x!\n", reg8);

    reg8 = ECSM.ECR.R;
    PSPRINTF("\n ECR = 0x%x!\n", reg8);

    reg8 = ECSM.ESR.R;
    PSPRINTF("\n ESR = 0x%x!\n", reg8);

    reg16 = ECSM.EEGR.R;
    PSPRINTF("\n EEGR = 0x%x!\n", reg16);

    reg32 = ECSM.PFEAR.R;
    PSPRINTF("\n PFEAR = 0x%x!\n", reg32);

    reg8 = ECSM.PFEMR.R;
    PSPRINTF("\n PFEMR = 0x%x!\n", reg8);

    reg8 = ECSM.PFEAT.R;
    PSPRINTF("\n PFEAT = 0x%x!\n", reg8);

    reg32 = ECSM.PFEDR.R;
    PSPRINTF("\n PFEDR = 0x%x!\n", reg32);

    reg32 = ECSM.PREAR.R;
    PSPRINTF("\n PREAR = 0x%x!\n", reg32);

    reg8 = ECSM.PRESR.R;
    PSPRINTF("\n PRESR = 0x%x!\n", reg8);

    reg8 = ECSM.PREMR.R;
    PSPRINTF("\n PREMR = 0x%x!\n", reg8);

    reg8 = ECSM.PREAT.R;
    PSPRINTF("\n PREAT = 0x%x!\n", reg8);

    reg32 = ECSM.PREDR.R;
    PSPRINTF("\n PREDR = 0x%x!\n", reg32);
}

/*******************************************************************************
 * @brief      ECSM_PFlashAbortStall_ISR
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ECSM_PFlashAbortStall_ISR(void)
{
    uint8_t val;

    /* Get all ECSM MIR flag, clear Flash RWE */
    val = ECSM.MIR.R;
    if ((val & (ECSM_MIR_FB0AI|ECSM_MIR_FB0SI)) != 0U)
    {
        CFLASH.MCR.R |= CFLASH_MCR_RWE;
    }
    if ((val & (ECSM_MIR_FB1AI|ECSM_MIR_FB1SI)) != 0U)
    {
        DFLASH.MCR.R |= DFLASH_MCR_RWE;
    }

    /* Clear all ECSM MIR flag */
    ECSM.MIR.R = ECSM_MIR_ALL_INT;

    LED_Set(LED1, LED_ON);
    PSPRINTF("\n ECSM MIR = 0x%x!\n", val);
}

/*******************************************************************************
 * @brief      Platform ECC Double Bit Detection
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ECSM_PFlashPRam_2BitDetection_ISR(void)
{
    if (ECSM.ESR.B.RNCE != 0U)
    {
        /* Clear flag */
        ECSM.ESR.R = ESR_RNCE;
        /* Read Register */
        ecc_ramAddress      = ECSM.PREAR.R;
        ecc_ramSyndrome     = ECSM.PRESR.R;
        ecc_ramMasterNum    = ECSM.PREMR.R;
        ecc_ramAttributes   = ECSM.PREAT.R;
        ecc_ramData         = ECSM.PREDR.R;
        /* Error correction */
        ((vuint32_t *)(ecc_ramAddress & ~0x3U))[0] = ecc_ramData;

        LED_Set(LED3, LED_ON);
        PSPRINTF("\n PRAM 2Bit ISR\n");
    }
    if (ECSM.ESR.B.FNCE != 0U)
    {
        /* Clear flag */
        ECSM.ESR.R = ESR_FNCE;
        /* Read Register */
        ecc_flashAddress      = ECSM.PFEAR.R;
        ecc_flashMasterNum    = ECSM.PFEMR.R;
        ecc_flashAttributes   = ECSM.PFEAT.R;
        ecc_flashData         = ECSM.PFEDR.R;
        /* Error correction */
        if ((CFLASH.MCR.R & CFLASH_MCR_EER) != 0U)
        {
            CFLASH.MCR.R |= CFLASH_MCR_EER;
            PSPRINTF("\n CFlash Clear EER\n");
        }

        if ((DFLASH.MCR.R & DFLASH_MCR_EER) != 0U)
        {
            DFLASH.MCR.R |= DFLASH_MCR_EER;
            PSPRINTF("\n DFlash Clear EER\n");
        }

        LED_Set(LED3, LED_ON);
        PSPRINTF("\n PFlash 2Bit ISR\n");
    }
}

/*******************************************************************************
 * @brief      Platform ECC Single Bit Correction
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ECSM_PFlashPRam_1BitCorrection_ISR(void)
{
    if (ECSM.ESR.B.R1BC != 0U)
    {
        /* Clear flag */
        ECSM.ESR.R = ESR_R1BC;
        /* Read Register */
        ecc_ramAddress      = ECSM.PREAR.R;
        ecc_ramSyndrome     = ECSM.PRESR.R;
        ecc_ramMasterNum    = ECSM.PREMR.R;
        ecc_ramAttributes   = ECSM.PREAT.R;
        ecc_ramData         = ECSM.PREDR.R;
        /* Error correction */
        ((vuint32_t *)(ecc_ramAddress & ~0x3U))[0] = ecc_ramData;

        LED_Set(LED1, LED_ON);
        PSPRINTF("\n PRAM 1Bit ISR\n");
    }
    if (ECSM.ESR.B.F1BC != 0U)
    {
        /* Clear flag */
        ECSM.ESR.R = ESR_F1BC;
        /* Read Register */
        ecc_flashAddress      = ECSM.PFEAR.R;
        ecc_flashMasterNum    = ECSM.PFEMR.R;
        ecc_flashAttributes   = ECSM.PFEAT.R;
        ecc_flashData         = ECSM.PFEDR.R;
        /* Error correction */
        if ((CFLASH.MCR.R & CFLASH_MCR_EDC) != 0U)
        {
            CFLASH.MCR.R |= (uint32_t)CFLASH_MCR_EDC;
            PSPRINTF("\n CFlash Clear EDC\n");
        }

        if ((DFLASH.MCR.R & DFLASH_MCR_EDC) != 0U)
        {
            DFLASH.MCR.R |= (uint32_t)DFLASH_MCR_EDC;
            PSPRINTF("\n DFlash Clear EDC\n");
        }

        LED_Set(LED1, LED_ON);
        PSPRINTF("\n PFlash 1Bit ISR\n");
    }
}

/*******************************************************************************
 * @brief      ECSM_INTC_Init
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void ECSM_INTC_Init(void)
{
    /* ECSM Abort/Stall Interrupt init */
    INTC_SoftInit(ECSM_PFlashAbortStall_ISR, (uint8_t)PFLASH_ABORT_STALL_IRQn, (uint8_t)PSR_PRI_4);
    INTC_SoftInit(ECSM_PFlashPRam_2BitDetection_ISR, (uint8_t)ECC_DBD_PFLASH_PRAM_IRQn, (uint8_t)PSR_PRI_4);
    INTC_SoftInit(ECSM_PFlashPRam_1BitCorrection_ISR, (uint8_t)ECC_SBC_PFLASH_PRAM_IRQn, (uint8_t)PSR_PRI_4);
    INTC_IRQ_Enable();
}

/*******************************************************************************
 * @brief      flash_lld.c -> CFlash_PageErase()
 * @param[in]  addr: CFlash address
 * @param[out] None
 * @retval     success, other: fail
 * @notapi
 *******************************************************************************/
static uint32_t CFlash_PageErase_RWE(uint32_t addr)
{
    uint32_t ret = 0x00000000U;
    uint32_t rwe;

    if ((CFLASH.MCR.R & (CFLASH_MCR_ERS | CFLASH_MCR_PGM)) != 0U)
    {
        /* If any P/E operation in progress return error */
        ret = 0x00000001U;
    }
    else
    {
        /* Set MCR ERS(Erase) bit */
        CFLASH.MCR.R = CFLASH_MCR_ERS;

        /* Interlock write */
        *( (volatile uint32_t *)(addr) ) = 0xFFFFFFFFU;

        /* Set MCR EHV(Enable High Voltage) bit, start operation */
        CFLASH.MCR.R |= CFLASH_MCR_EHV;

        /* Read-while-Write event Error */
        rwe = *((vuint32_t *)addr); /* PRQA S 2983 */

        /* Loop to wait for DONE = 1 */
        while ((CFLASH.MCR.R & CFLASH_MCR_DONE) != CFLASH_MCR_DONE)
        {
            ;
        }

        /* Check PEG(Program/Erase Good) flag */
        if ((CFLASH.MCR.R & CFLASH_MCR_PEG) != CFLASH_MCR_PEG)
        {
            ret = 0x000000FFU;
        }

        /* Reset EHV */
        CFLASH.MCR.R = CFLASH_MCR_ERS;

        /* Reset ERS */
        CFLASH.MCR.R = CFLASH_MCR_NULL;

        /* Loop to wait for ERS = 0 */
        while ((CFLASH.MCR.R & CFLASH_MCR_ERS) == CFLASH_MCR_ERS)
        {
            ;
        }
    }
    return ret;
}

/*******************************************************************************
 * @brief      flash_lld.c -> CFlash_BlockErase()
 * @param[in]  lsl/msl: uint32_t
 *             hsl: uint32_t
 * @param[out] None
 * @ret     0: success, other: fail
 * @notapi
 *******************************************************************************/
static uint32_t CFlash_BlockErase_RWE(uint32_t lsl, uint32_t msl, uint32_t hsl) /* PRQA S 3219 */
{
    uint32_t ret = 0x00000000U;
    uint32_t rwe;
    uint32_t low_sel,mid_sel,high_sel;

    low_sel = lsl;
    mid_sel = msl;
    high_sel = hsl;

    if ((CFLASH.MCR.R & (CFLASH_MCR_ERS | CFLASH_MCR_PGM)) != 0U)
    {
        /* If any P/E operation in progress return error */
        ret = 0x00000001U;
    }
    else
    {
        /* Set MCR ERS(Erase) bit */
        CFLASH.MCR.R = CFLASH_MCR_ERS;

        /* Prepare low and middle to select blocks */
        low_sel &= CFLASH_LMS_L0_5;
        mid_sel &= CFLASH_LMS_M0_1;
        high_sel &= CFLASH_HBS_NULL;

        /* Write the block selection registers */
        CFlash_SelectBlocks(low_sel, mid_sel, high_sel);

        /* Interlock write */
        *( (volatile uint32_t *)(CFLASH_SECTOR0_START) ) = 0xFFFFFFFFU; /* PRQA S 2810 */
        
        /* Set MCR EHV(Enable High Voltage) bit, start operation */
        CFLASH.MCR.R |= CFLASH_MCR_EHV;

        /* Read-while-Write event Error */
        rwe = *((vuint32_t *)CFLASH_SECTOR0_START); /* PRQA S 2983, 2810 */

        /* Loop to wait for DONE = 1 */
        while ((CFLASH.MCR.R & CFLASH_MCR_DONE) != CFLASH_MCR_DONE)
        {
            ;
        }

        /* Check PEG(Program/Erase Good) flag */
        if ((CFLASH.MCR.R & CFLASH_MCR_PEG) != CFLASH_MCR_PEG)
        {
            ret = 0x000000FFU;
        }
        
        /* Reset EHV */
        CFLASH.MCR.R = CFLASH_MCR_ERS;

        /* Reset ERS */
        CFLASH.MCR.R = CFLASH_MCR_NULL;

		/* Loop to wait for ERS = 0 */
        while ((CFLASH.MCR.R & CFLASH_MCR_ERS) == CFLASH_MCR_ERS)
        {
            ;
        }

        /* Write the block selection registers, UnSelect blocks */
        CFlash_UnSelectBlocks();
    }

    return ret;
}

/*******************************************************************************
 * @brief      flash_lld.c -> CFlash_DoubleWordProgram().
 * @param[in]  addr: destination address
 *             word1: word data 1
 *             word2: word data 2
 * @param[out] None
 * @ret     0: success, other: fail
 * @notapi
 *******************************************************************************/
static uint32_t CFlash_DwProgram_RWE(uint32_t word1, uint32_t word2, uint32_t addr)
{
    uint32_t ret = 0x00000000U;
    uint32_t counter;                       /* Loop variable counter */
    uint32_t rwe;

    /* Check operation */
    if ((CFLASH.MCR.R & (CFLASH_MCR_ERS | CFLASH_MCR_PGM)) != 0U)
    {
        /* Reuse variable counter for checking erase suspend */
        counter = CFLASH.MCR.R & (CFLASH_MCR_ERS | CFLASH_MCR_ESUS);
        if (counter == (CFLASH_MCR_ERS | CFLASH_MCR_ESUS))
        {
            /* Erase has been suspended
             *      and program operation can be performed. */
        }
        else
        {
            /* If any P/E operation in progress return error */
            ret = 0x00000001U;
        }
    }

    /* Program sequence */
    if (ret == 0x00000000U)
    {
        /* Set MCR PGM(Program) bit */
        CFLASH.MCR.R = CFLASH_MCR_PGM;

        /* Write interlock */
        *( (vuint32_t *)(addr) ) = word1;
        *( (vuint32_t *)(addr + 4U) ) = word2;

        /* Set MCR EHV(Enable High Voltage) bit, start operation */
        CFLASH.MCR.R |= CFLASH_MCR_EHV;

        /* Read-while-Write event Error */
        rwe = *((vuint32_t *)addr); /* PRQA S 2983 */

        /* Loop to wait for DONE = 1 */
        while ((CFLASH.MCR.R & CFLASH_MCR_DONE) != CFLASH_MCR_DONE)
        {
            ;
        }

        /* Check PEG(Program/Erase Good) flag */
        if ((CFLASH.MCR.R & CFLASH_MCR_PEG) != CFLASH_MCR_PEG)
        {
            ret = 0x000000FFU;
        }

        /* Reset EHV */
        CFLASH.MCR.R = CFLASH_MCR_PGM;

        /* Reset PGM */
        CFLASH.MCR.R = CFLASH_MCR_NULL;

        /* Loop to wait for PGM = 0 */
        while ((CFLASH.MCR.R & CFLASH_MCR_PGM) == CFLASH_MCR_PGM)
        {
            ;
        }
    }

    return ret;
}

/*******************************************************************************
 * @brief      flash_lld.c -> DFlash_BlockErase().
 * @param[in]  lsl: uint32_t
 * @param[out] None
 * @ret     0: success, other: fail
 * @notapi
 *******************************************************************************/
static uint32_t DFlash_BlockErase_RWE(uint32_t lsl)
{
    uint32_t ret = 0x00000000U;
    uint32_t rwe;
    uint32_t low_sel;

    low_sel = lsl;

    if ((DFLASH.MCR.R & (DFLASH_MCR_ERS | DFLASH_MCR_PGM)) != 0U)
    {
        /* If any P/E operation in progress return error */
        ret = 0x00000001U;
    }
    else
    {
        /* Set MCR ERS(Erase) bit */
        DFLASH.MCR.R = DFLASH_MCR_ERS;

        /* Prepare low and middle to select blocks */
        low_sel &= DFLASH_LMS_L0_3;

        /* Write the block selection registers */
        DFlash_SelectBlocks(low_sel);

        /* Interlock write */
        *((volatile uint32_t *)(DFLASH_SECTOR0_START)) = 0xFFFFFFFFU;

        /* Set MCR EHV(Enable High Voltage) bit, start operation */
        DFLASH.MCR.R |= DFLASH_MCR_EHV;

        /* Read-while-Write event Error */
        rwe = *((vuint32_t *)DFLASH_SECTOR0_START); /* PRQA S 2983 */

        /* Loop to wait for DONE = 1 */
        while ((DFLASH.MCR.R & DFLASH_MCR_DONE) != DFLASH_MCR_DONE)
        {
            ;
        }

        /* Check PEG(Program/Erase Good) flag */
        if ((DFLASH.MCR.R & DFLASH_MCR_PEG) != DFLASH_MCR_PEG)
        {
            ret = 0x000000FFU;
        }

        /* Reset EHV */
        DFLASH.MCR.R = DFLASH_MCR_ERS;

        /* Reset ERS */
        DFLASH.MCR.R = DFLASH_MCR_NULL;

        /* Write the block selection registers, UnSelect blocks */
        DFlash_UnSelectBlocks();
    }

    return ret;
}

/*******************************************************************************
 * @brief      DFlash Double Word Program.
 *              If you want to program the block, you must [unlock]
 *                  the block.
 * @param[in]  addr: destination address
 *             size: program size
 *             data: source data
 * @param[out] None
 * @ret     0: success, other: fail
 * @notapi
 *******************************************************************************/
static uint32_t DFlash_DwProgram_RWE(uint32_t word1, uint32_t word2, uint32_t addr)
{
    uint32_t ret = 0x00000000U;
    uint32_t counter;                       /* Loop variable counter */
    uint32_t rwe;

    /* Check operation */
    if ((DFLASH.MCR.R & (DFLASH_MCR_ERS | DFLASH_MCR_PGM)) != 0U)
    {
        /* Reuse variable counter for checking erase suspend */
        counter = DFLASH.MCR.R & (DFLASH_MCR_ERS | DFLASH_MCR_ESUS);
        if (counter == (DFLASH_MCR_ERS | DFLASH_MCR_ESUS))
        {
            /* Erase has been suspended
             *      and program operation can be performed. */
        }
        else
        {
            /* If any P/E operation in progress return error */
            ret = 0x00000001U;
        }
    }

    /* Program sequence */
    if (ret == 0x00000000U)
    {
        /* Set MCR PGM(Program) bit */
        DFLASH.MCR.R = DFLASH_MCR_PGM;

        /* Write interlock */
        *( (vuint32_t *)(addr) ) = word1;
        *( (vuint32_t *)(addr + 4U) ) = word2;

        /* Set MCR EHV(Enable High Voltage) bit, start operation */
        DFLASH.MCR.R |= DFLASH_MCR_EHV;

        /* Read-while-Write event Error */
        rwe = *((vuint32_t *)DFLASH_SECTOR0_START); /* PRQA S 2983 */

        /* Loop to wait for DONE = 1 */
        while ((DFLASH.MCR.R & DFLASH_MCR_DONE) != DFLASH_MCR_DONE)
        {
            ;
        }

        /* Check PEG(Program/Erase Good) flag */
        if ((DFLASH.MCR.R & DFLASH_MCR_PEG) != DFLASH_MCR_PEG)
        {
            ret = 0x000000FFU;
        }

        /* Reset EHV */
        DFLASH.MCR.R = DFLASH_MCR_PGM;

        /* Reset PGM */
        DFLASH.MCR.R = DFLASH_MCR_NULL;

        /* Loop to wait for PGM = 0 */
        while ((DFLASH.MCR.R & DFLASH_MCR_PGM) == DFLASH_MCR_PGM)
        {
            ;
        }
    }

    return ret;
}

/*******************************************************************************
 * @brief      ECSM Miscellaneous Interrupt test.
 *             FB0AI: Flash Bank 0 Abort Interrupt(CFlash)
 *             FB0SI: Flash Bank 0 Stall Interrupt(CFlash)
 *             FB1AI: Flash Bank 1 Abort Interrupt(DFlash)
 *             FB1SI: Flash Bank 1 Stall Interrupt(DFlash)
 *             note:  CFlash cannot erase/programming CFlash,
 *                    CFlash programming itself causes IVOP6...
 * @param[in]  None
 * @param[out] None
 * @ret     None
 * @notapi
 *******************************************************************************/
static void ECSM_PFlash_MIR_Demo(uint32_t addr) /* PRQA S 3219 */
{
    uint32_t ret;
    uint32_t pflash_t;
    uint32_t reg32;
    uint32_t lowBlock;
    uint32_t midBlock;
    uint32_t highBlock;
    uint32_t const test_buf[2] = {0x01234567U, 0x89ABCDEFU};

    /* Clear all ECSM MIR flag. */
    ECSM.MIR.R = ECSM_MIR_ALL_INT;

    /* Determine whether it is CFlash or DFlash */
    pflash_t = PFlash_BankType(addr);
    if (CFLASH_BANK0 == pflash_t)
    {
        PSPRINTF("\n CFlash MIR Demo!\n");

        /* Unlock all blocks */
        CFlash_UnlockBlocksInit();

        /* Determine which block of Flash it is */
        ret = CFlash_GetBlockSelect(addr, &lowBlock, &midBlock, &highBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n CFlash_GetBlockSelect Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Enable Stall ISR, Disable Abort ISR */
        reg32 = CFLASH.PFCR0.R & (~PFCR_BK_RWWC_M);
        CFLASH.PFCR0.R = (reg32 | PFCR_BK_RWWC_6);

        /* Erase Flash */
        ret = CFlash_PageErase_RWE(addr);
        if (ret != 0U)
        {
            PSPRINTF("\n CFlash Erase Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Enable Stall ISR, Enable Abort ISR */
        reg32 = CFLASH.PFCR0.R & (~PFCR_BK_RWWC_M);
        CFLASH.PFCR0.R = (reg32 | PFCR_BK_RWWC_4);

        /* Program Flash */
        ret = CFlash_DwProgram_RWE(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n CFlash Program Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Disable Stall ISR, Disable Abort ISR */
        reg32 = CFLASH.PFCR0.R & (~PFCR_BK_RWWC_M);
        CFLASH.PFCR0.R = (reg32 | PFCR_BK_RWWC_7);
    }
    else if (DFLASH_BANK1 == pflash_t)
    {
        PSPRINTF("\n DFlash MIR Demo!\n");

        /* Unlock all blocks */
        DFlash_UnlockBlocksInit();

        /* Determine which block of Flash it is */
        ret = DFlash_GetBlockSelect(addr, &lowBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n DFlash_GetBlockSelect Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Enable Stall ISR, Disable Abort ISR */
        reg32 = (CFLASH.PFCR1.R) & (~PFCR_BK_RWWC_M);
        CFLASH.PFCR1.R = (reg32 | PFCR_BK_RWWC_6);

        /* Erase Flash */
        ret = DFlash_BlockErase_RWE(lowBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n DFlash Erase Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Enable Stall ISR, Enable Abort ISR */
        reg32 = (CFLASH.PFCR1.R) & (~PFCR_BK_RWWC_M);
        CFLASH.PFCR1.R = (reg32 | PFCR_BK_RWWC_4);

        /* Program Flash */
        ret = DFlash_DwProgram_RWE(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n DFlash Program Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Disable Stall ISR, Disable Abort ISR */
        reg32 = (CFLASH.PFCR1.R) & (~PFCR_BK_RWWC_M);
        CFLASH.PFCR1.R = (reg32 | PFCR_BK_RWWC_7);
    }
    else
    {
        PSPRINTF("\n Flash Addr error: 0x%x!\n", addr);
        ECSM_Error();
    }
}

/*******************************************************************************
 * @brief      ECSM ECC Configuration test.
 *             ER1BR: Enable SRAM 1-bit Reporting
 *             EF1BR: Enable Flash 1-bit Reporting
 *             ERNCR: Enable SRAM Non-Correctable Reporting
 *             EFNCR: Enable Flash Non-Correctable Reporting
 * @param[in]  addr: CFlash/DFlash/SRAM
 * @param[out] None
 * @ret     None
 * @notapi
 *******************************************************************************/
static void ECSM_ECC_Demo(uint32_t addr) /* PRQA S 3219 */
{
    uint32_t ret;
    uint32_t tmp_val;        /* Temporary variable value */
    uint32_t addr_t;        /* Enter the address range type */
    uint32_t lowBlock;
    uint32_t midBlock;
    uint32_t highBlock;
    uint32_t test_buf[2] = {0x01234567U, 0x89ABCDEFU};

    /* Determine whether it is PFlash or RAM */
    addr_t = PFlash_BankType(addr);

    if (CFLASH_BANK0 == addr_t)
    {
        PSPRINTF("\n ---CFlash ECC 1-bit Demo---!\n");

        /* Determine which block of Flash it is */
        ret = CFlash_GetBlockSelect(addr, &lowBlock, &midBlock, &highBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit CFlash_GetBlockSelect Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Unlock the corresponding block */
        CFlash_UnlockSelectBlock(lowBlock, midBlock, highBlock);

        /* Erase Flash */
        ret = CFlash_BlockErase(lowBlock, midBlock, highBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit CFlash Erase Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;

        /* Enable ECR all */
        ret = ECSM_ECC_ECR_Config(ECR_ALL, ECR_EN);
        if (ret != 0U)
        {
            PSPRINTF("\n ECSM ECR Config Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Program Flash */
        ret = CFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit CFlash Program1 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }
        test_buf[0] = 0x00234567U;   /* 1-bit */
        ret = CFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit CFlash Program2 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Read Flash(Reading data will trigger an existing ECC error) */
        PSPRINTF("\n 1-bit Read CFlash addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        PSPRINTF("\n 1-bit Read CFlash addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 4U)); /* PRQA S 2982 */

        /* Lock all blocks */
        CFlash_LockBlocksInit();

        PSPRINTF("\n ---CFlash ECC 2-bit Demo---!\n");

        /* Determine which block of Flash it is */
        ret = CFlash_GetBlockSelect(addr, &lowBlock, &midBlock, &highBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit CFlash_GetBlockSelect Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Unlock the corresponding block */
        CFlash_UnlockSelectBlock(lowBlock, midBlock, highBlock);

        /* Erase Flash */
        ret = CFlash_BlockErase(lowBlock, midBlock, highBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit CFlash Erase Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;

        /* Enable ECR all */
        ret = ECSM_ECC_ECR_Config(ECR_ALL, ECR_EN);
        if (ret != 0U)
        {
            PSPRINTF("\n ECSM ECR Config Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Program Flash */
        test_buf[0] = 0x01234567U;
        ret = CFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit CFlash Program1 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }
        test_buf[0] = 0x00034567U;   /* 2-bit */
        ret = CFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit CFlash Program2 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Read Flash(Reading data will trigger an existing ECC error) */
        PSPRINTF("\n 2-bit Read CFlash addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        PSPRINTF("\n 2-bit Read CFlash addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 4U)); /* PRQA S 2983 */

        /* Lock all blocks */
        CFlash_LockBlocksInit();
    }
    else if (DFLASH_BANK1 == addr_t)
    {
        PSPRINTF("\n ---DFlash ECC 1-bit Demo---!\n");

        /* Determine which block of Flash it is */
        ret = DFlash_GetBlockSelect(addr, &lowBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit DFlash_GetBlockSelect Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Unlock the corresponding block */
        DFlash_UnlockSelectBlock(lowBlock);

        /* Erase Flash */
        ret = DFlash_BlockErase(lowBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit DFlash Erase Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;

        /* Enable ECR all */
        ret = ECSM_ECC_ECR_Config(ECR_ALL, ECR_EN);
        if (ret != 0U)
        {
            PSPRINTF("\n ECSM ECR Config Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Program Flash */
        ret = DFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit DFlash Program1 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }
        test_buf[0] = 0x00234567U;   /* 1-bit */
        ret = DFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 1-bit DFlash Program2 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Read Flash(Reading data will trigger an existing ECC error) */
        PSPRINTF("\n 1-bit Read DFlash addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        PSPRINTF("\n 1-bit Read DFlash addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 4U)); /* PRQA S 2982 */

        /* Lock all blocks */
        DFlash_LockBlocksInit();

        PSPRINTF("\n ---DFlash ECC 2-bit Demo---!\n");

        /* Determine which block of Flash it is */
        ret = DFlash_GetBlockSelect(addr, &lowBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit DFlash_GetBlockSelect Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Unlock the corresponding block */
        DFlash_UnlockSelectBlock(lowBlock);

        /* Erase Flash */
        ret = DFlash_BlockErase(lowBlock);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit DFlash Erase Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;

        /* Enable ECR all */
        ret = ECSM_ECC_ECR_Config(ECR_ALL, ECR_EN);
        if (ret != 0U)
        {
            PSPRINTF("\n ECSM ECR Config Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Program Flash */
        test_buf[0] = 0x01234567U;
        ret = DFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit DFlash Program1 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }
        test_buf[0] = 0x00034567U;   /* 2-bit */
        ret = DFlash_DwProgram(test_buf[0], test_buf[1], addr);
        if (ret != 0U)
        {
            PSPRINTF("\n 2-bit DFlash Program2 Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* Read Flash(Reading data will trigger an existing ECC error) */
        PSPRINTF("\n 2-bit Read DFlash addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        PSPRINTF("\n 2-bit Read DFlash addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 4U)); /* PRQA S 2983 */

        /* Lock all blocks */
        DFlash_LockBlocksInit();
    }
    else if (PSRAM_ADDR == addr_t)
    {
        PSPRINTF("\n ---SRAM ECC 1-bit Demo---!\n");
        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;
        /* Enable SRAM 1-bit Reporting */
        ret = ECSM_ECC_ECR_Config(ECR_ER1BR, ECR_EN);
        if (ret != 0U)
        {
            PSPRINTF("\n ECSM ECR Config Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* One */
        PSPRINTF("\n 1-bit Once!!!\n");
        /* Force SRAM One 1-bit Data Inversion */
        ECSM_SRAM_Force1BitOne(EEGR_ERRBIT0_SRAM0);
        /* Write SRAM */
        *((vuint32_t *)(addr))       = 0x5555AAAAU;
        *((vuint32_t *)(addr + 8U))  = 0x3333CCCCU;
        /* Stop Error Inserting */
        ECSM_SRAM_ForceStop();
        /* Read SRAM addr0(Event Should Occur) */
        PSPRINTF("\n 1-bit Read SRAM addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        /* Read SRAM addr1(Event Should not Occur) */
        PSPRINTF("\n 1-bit Read SRAM addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 8U)); /* PRQA S 2982 */
        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;

        /* Continuous */
        PSPRINTF("\n 1-bit Continuous!!!\n");
        /* Force SRAM Continuous 1-bit Data Inversions */
        ECSM_SRAM_Force1BitCont(EEGR_ERRBIT5_SRAM5);
        /* Write SRAM */
        *((vuint32_t *)(addr))      = 0x5555AAAAU;
        *((vuint32_t *)(addr + 8U))  = 0x3333CCCCU;
        /* Stop Error Inserting */
        ECSM_SRAM_ForceStop();
        /* Read SRAM addr0(Event Should Occur) */
        PSPRINTF("\n 1-bit Read SRAM addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        /* Read SRAM addr1(Event Should Occur) */
        PSPRINTF("\n 1-bit Read SRAM addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 8U)); /* PRQA S 2982 */

        PSPRINTF("\n ---SRAM ECC 2-bit Demo---!\n");
        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;
        /* Enable SRAM Non-Correctable Reporting */
        ret = ECSM_ECC_ECR_Config(ECR_ERNCR, ECR_EN);
        if (ret != 0U)
        {
            PSPRINTF("\n ECSM ECR Config Fail, 0x%x!\n", ret);
            ECSM_Error();
        }

        /* One */
        PSPRINTF("\n 2-bit Once!!!\n");
        /* Force SRAM One Non-correctable Data Inversions */
        ECSM_SRAM_Force2BitOne(EEGR_ERRBIT0_SRAM0);
        /* Write SRAM */
        *((vuint32_t *)(addr))      = 0x5555AAAAU;
        *((vuint32_t *)(addr + 8U))  = 0x3333CCCCU;
        /* Stop Error Inserting */
        ECSM_SRAM_ForceStop();
        /* Read SRAM addr0(Event Should Occur) */
        PSPRINTF("\n 2-bit Read SRAM addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        /* Read SRAM addr1(Event Should not Occur) */
        PSPRINTF("\n 2-bit Read SRAM addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 8U)); /* PRQA S 2982 */
        /* Clear ESR interrupt flag */
        ECSM.ESR.R = ESR_ALL;

        /* Continuous */
        PSPRINTF("\n 2-bit Continuous!!!\n");
        /* Force SRAM Continuous Non-correctable Data Inversions */
        ECSM_SRAM_Force2BitCont(EEGR_ERRBIT5_SRAM5);
        /* Write SRAM */
        *((vuint32_t *)(addr))      = 0x5555AAAAU;
        *((vuint32_t *)(addr + 8U))  = 0x3333CCCCU;
        /* Stop Error Inserting */
        ECSM_SRAM_ForceStop();
        /* Read SRAM addr0(Event Should Occur) */
        PSPRINTF("\n 2-bit Read SRAM addr0!\n");
        tmp_val = *((vuint32_t *)addr); /* PRQA S 2982 */
        /* Read SRAM addr1(Event Should Occur) */
        PSPRINTF("\n 2-bit Read SRAM addr1!\n");
        tmp_val = *((vuint32_t *)(addr + 8U)); /* PRQA S 2983 */
    }
    else
    {
        PSPRINTF("\n ECC_Demo Address error: 0x%x!\n", addr);
        ECSM_Error();
    }
}


/*******************************************************************************
 * @brief      ECSM_demo
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
void ECSM_demo(void)
{
	/* Function: Read ECSM register and Print. */
#if ECSM_READ_REG_SW
    ECSM_RegisterRead_Demo();
#endif

    ECSM_INTC_Init();

    /* Function: CFlash ECSM Abort & Stall Interrupt Demo .
     * (Note: CFlash Demo need Run in RAM.) */
#if ECSM_MIR_CFlash_SW
    ECSM_PFlash_MIR_Demo(CFLASH_SECTOR4_START);
#endif

    /* Fucntion: DFlash ECSM Abort & Stall Interrupt Demo . */
#if ECSM_MIR_DFlash_SW
    ECSM_PFlash_MIR_Demo(DFLASH_SECTOR0_START);
#endif

    /* Function: CFlash 1-bit & Non-Correctable error Demo .
     * (Note: CFlash Demo need Run in RAM.) */
#if ECSM_ECC_CFlash_SW
    ECSM_ECC_Demo(CFLASH_SECTOR4_START);
#endif

    /* Function: DFlash 1-bit & Non-Correctable error Demo . */
#if ECSM_ECC_DFlash_SW
    ECSM_ECC_Demo(DFLASH_SECTOR0_START);
#endif

    /* Function: SRAM 1-bit & Non-Correctable error Demo . */
#if ECSM_ECC_SRAM_SW
    ECSM_ECC_Demo(0x40037E00U);
#endif
}
